package com.example.demo.filters;

import com.example.demo.domain.ResultMessage;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import io.github.resilience4j.ratelimiter.RateLimiter;
import io.github.resilience4j.ratelimiter.RateLimiterRegistry;
import io.vavr.control.Try;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;

import java.util.concurrent.Callable;

@Component
public class RateLimiterFilter extends ZuulFilter {

    @Autowired
    private RateLimiterRegistry rateLimiterRegistry;

    private static final String USER_PRE = "/u/";

    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return FilterConstants.PRE_DECORATION_FILTER_ORDER + 30;
    }

    @Override
    public boolean shouldFilter() {
        RequestContext ctx = RequestContext.getCurrentContext();
        String uri = ctx.getRequest().getRequestURI();
        return uri.startsWith(USER_PRE);
    }

    @Override
    public Object run() throws ZuulException {
        //获取Resilience4j限速器
        RateLimiter userRateLimiter = rateLimiterRegistry.rateLimiter("user");
        //限速器逻辑
        Callable<ResultMessage> call1 = () -> new ResultMessage(true, "通过");
        //绑定限速器
        Callable<ResultMessage> call2 = RateLimiter.decorateCallable(userRateLimiter, call1);
        //尝试获取结果
        Try<ResultMessage> tryResult = Try.of(call2::call)
                //降级逻辑
                .recover(ex -> new ResultMessage(false, "超出所限流量"));

        ResultMessage result = tryResult.get();
        if (result.isSuccess()) {
            return null;
        }
        RequestContext ctx = RequestContext.getCurrentContext();
        ctx.setSendZuulResponse(false);
        ctx.setResponseStatusCode(HttpStatus.TOO_MANY_REQUESTS.value());
        ctx.getResponse().setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
        ObjectMapper mapper = new ObjectMapper();
        String body = null;

        try {
            body = mapper.writeValueAsString(result);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        ctx.setResponseBody(body);
        return null;
    }
}
